﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;

namespace terav_totris
{
    /// <summary>
    /// Tetrise kujundite ülesehitus, meetodid praeguse ja 
    /// järgmise kujundi joonistamiseks mänguväljale, samuti
    /// kokkupõrgete tuvastamiseks teiste kujundite ja väljaku
    /// servadega.
    /// </summary>
    class Kujund : IJoonistatav, ILiikuv
    {
        // Kujundite algandmed. Iga klotsi suurus on 30x30 pikslit.
        // Kujundit sisaldav 4x4 klotsi suurune ruudustik hakkab liikuma
        // mänguväljaku 1. tulbast, 4. realt 
        public const int klotsiSuurus = 30;
        public const int algusTulp = 0;
        public const int algusRida = 3;


        // Kokkupõrgete olemasolu
        public bool AllKokkuPorge;
        public bool YlalKokkuPorge;
        public bool ParemKokkuPorge;
        public bool ParemPoordeKokkuPorge;
        public bool VasakPoordeKokkuPorge;

        // Kujundeid kirjeldavad omadused. Privaatmuutujad,
        // väljapoolt ligipääsetavad get-set-meetodil

        #region saaJaAnna

        private int liik;
        public int Liik
        {
            get { return liik; }
            set { liik = value; }
        }

        private int jargmiseLiik;
        public int JargmiseLiik
        {
            get { return jargmiseLiik; }
            set { jargmiseLiik = value; }
        }

        private int asend;
        public int Asend
        {
            get { return asend; }
            set { asend = value; }
        }

        private int jargmiseAsend;
        public int JargmiseAsend
        {
            get { return jargmiseAsend; }
            set { jargmiseAsend = value; }
        }

        private int asuKohaRida;
        public int AsuKohaRida
        {
            get { return asuKohaRida; }
            set { asuKohaRida = value; }
        }

        private int asuKohaTulp;
        public int AsuKohaTulp
        {
            get { return asuKohaTulp; }
            set { asuKohaTulp = value; }
        }


        #endregion

        // Kujundite valik ja asendid on koondatud neljamõõtmelisse massiivi.
        // Esimene mõõde 0-6 tähistab kujundi liiki.
        // Teine mõõde 0-3 tähistab kujundi asendit.
        // Kolmas mõõde 0-3 tähistab kujundit sisaldava 4x4 ruudustiku rida
        // Neljas mõõde 0-3 tähistab kujundit sisaldava 4x4 ruudustiku tulpa

        #region kujundiliikide massiiv
        public static readonly int[, , ,] andmed = new int[7, 4, 4, 4]
        {
            // liik I = 0
            {
                // asend = 0
                {
                    { 1, 0, 0, 0 },
                    { 1, 0, 0, 0 },
                    { 1, 0, 0, 0 },
                    { 1, 0, 0, 0 }
                },
                // asend = 1
                {
                    { 0, 0, 0, 0 },
                    { 1, 1, 1, 1 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                },
                // asend = 2
                {
                    { 1, 0, 0, 0 },
                    { 1, 0, 0, 0 },
                    { 1, 0, 0, 0 },
                    { 1, 0, 0, 0 }
                },
                // asend = 3
                {
                    { 0, 0, 0, 0 },
                    { 1, 1, 1, 1 },
                    { 0, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                }
            }, // liigi I lõpp


            // liik O = 1
            {
                // asend = 0
                {
                    { 0, 0, 0, 0 },
                    { 1, 1, 0, 0 },
                    { 1, 1, 0, 0 },
                    { 0, 0, 0, 0 }
                },
                // asend = 1
                {
                    { 0, 0, 0, 0 },
                    { 1, 1, 0, 0 },
                    { 1, 1, 0, 0 },
                    { 0, 0, 0, 0 }
                },
                // asend = 2
                {
                    { 0, 0, 0, 0 },
                    { 1, 1, 0, 0 },
                    { 1, 1, 0, 0 },
                    { 0, 0, 0, 0 }
                },
                // asend = 3
                {
                    { 0, 0, 0, 0 },
                    { 1, 1, 0, 0 },
                    { 1, 1, 0, 0 },
                    { 0, 0, 0, 0 }
                }
            }, // liigi O lõpp


            // liik L = 2
            {
                // asend = 0
                {
                    { 1, 0, 0, 0 },
                    { 1, 0, 0, 0 },
                    { 1, 1, 0, 0 },
                    { 0, 0, 0, 0 }
                },
                // asend = 1
                {
                    { 0, 0, 0, 0 },
                    { 0, 0, 1, 0 },
                    { 1, 1, 1, 0 },
                    { 0, 0, 0, 0 }
                },
                // asend = 2
                {
                    { 1, 1, 0, 0 },
                    { 0, 1, 0, 0 },
                    { 0, 1, 0, 0 },
                    { 0, 0, 0, 0 }
                },
                // asend = 3
                {
                    { 0, 0, 0, 0 },
                    { 1, 1, 1, 0 },
                    { 1, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                }
            }, // liigi L lõpp


            // liik J = 3
            {
                // asend = 0
                {
                    { 0, 1, 0, 0 },
                    { 0, 1, 0, 0 },
                    { 1, 1, 0, 0 },
                    { 0, 0, 0, 0 }
                },
                // asend = 1
                {
                    { 0, 0, 0, 0 },
                    { 1, 1, 1, 0 },
                    { 0, 0, 1, 0 },
                    { 0, 0, 0, 0 }
                },
                // asend = 2
                {
                    { 1, 1, 0, 0 },
                    { 1, 0, 0, 0 },
                    { 1, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                },
                // asend = 3
                {
                    { 0, 0, 0, 0 },
                    { 1, 0, 0, 0 },
                    { 1, 1, 1, 0 },
                    { 0, 0, 0, 0 }
                }
            }, // liigi J lõpp


            // liik T = 4
            {
                // asend = 0
                {
                    { 1, 0, 0, 0 },
                    { 1, 1, 0, 0 },
                    { 1, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                },
                // asend = 1
                {
                    { 0, 0, 0, 0 },
                    { 0, 1, 0, 0 },
                    { 1, 1, 1, 0 },
                    { 0, 0, 0, 0 }
                },
                // asend = 2
                {
                    { 0, 1, 0, 0 },
                    { 1, 1, 0, 0 },
                    { 0, 1, 0, 0 },
                    { 0, 0, 0, 0 }
                },
                // asend = 3
                {
                    { 0, 0, 0, 0 },
                    { 1, 1, 1, 0 },
                    { 0, 1, 0, 0 },
                    { 0, 0, 0, 0 }
                }
            }, // liigi T lõpp


            // liik S = 5
            {
                // asend = 0
                {
                    { 1, 0, 0, 0 },
                    { 1, 1, 0, 0 },
                    { 0, 1, 0, 0 },
                    { 0, 0, 0, 0 }
                },
                // asend = 1
                {
                    { 0, 0, 0, 0 },
                    { 0, 1, 1, 0 },
                    { 1, 1, 0, 0 },
                    { 0, 0, 0, 0 }
                },
                // asend = 2
                {
                    { 1, 0, 0, 0 },
                    { 1, 1, 0, 0 },
                    { 0, 1, 0, 0 },
                    { 0, 0, 0, 0 }
                },
                // asend = 3
                {
                    { 0, 0, 0, 0 },
                    { 0, 1, 1, 0 },
                    { 1, 1, 0, 0 },
                    { 0, 0, 0, 0 }
                }
            }, // liigi S lõpp


            // liik Z = 6
            {
                // asend = 0
                {
                    { 0, 0, 0, 0 },
                    { 1, 1, 0, 0 },
                    { 0, 1, 1, 0 },
                    { 0, 0, 0, 0 }
                },
                // asend = 1
                {
                    { 0, 1, 0, 0 },
                    { 1, 1, 0, 0 },
                    { 1, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                },
                // asend = 2
                {
                    { 0, 0, 0, 0 },
                    { 1, 1, 0, 0 },
                    { 0, 1, 1, 0 },
                    { 0, 0, 0, 0 }
                },
                // asend = 3
                {
                    { 0, 1, 0, 0 },
                    { 1, 1, 0, 0 },
                    { 1, 0, 0, 0 },
                    { 0, 0, 0, 0 }
                }
            } // liigi Z lõpp
        }; // kujundite massiivi lõpp
        #endregion

        public Kujund()
        {
            // Konstruktori sisu on eraldi meetodis.
            // Siis saab seda ka mujal kasutada.
            TekitaKujund();
        }


        /// <summary>
        /// Tekitab uue kujundi, valides liigi ja asendi juhuarvude generaatori abil 
        /// ja määrates kujundit sisaldava 4x4 ruudustiku algse asukoha. Ühtlasi valib
        /// kohe ka järgmise kujundi liigi ja asendi.
        /// </summary>
        public void TekitaKujund()
        {
            Random juhuArvudeGeneraator = new Random();

            liik = (int)juhuArvudeGeneraator.Next(0, 7);
            asend = (int)juhuArvudeGeneraator.Next(0, 4);

            jargmiseLiik = (int)juhuArvudeGeneraator.Next(0, 7);
            jargmiseAsend = (int)juhuArvudeGeneraator.Next(0, 4);

            asuKohaTulp = algusTulp;
            asuKohaRida = algusRida;
        }


        /// <summary>
        /// Kui järgmine kujund hakkab mänguväljale tulema, 
        /// kopeeritakse järgmise kujundi omadused praeguse kujundi 
        /// omadeks. Omakorda saab uued väärtused ka järgmine kujund.
        /// </summary>
        public void JargmineValmis()
        {
            liik = jargmiseLiik;
            asend = jargmiseAsend;

            asuKohaTulp = algusTulp;
            asuKohaRida = algusRida;

            Random juhuArvudeGeneraator = new Random();

            jargmiseLiik = (int)juhuArvudeGeneraator.Next(0, 7);
            jargmiseAsend = (int)juhuArvudeGeneraator.Next(0, 4);
        }


        /// <summary>
        /// Joonistab klotsi ja paigutab selle mänguväljale. 
        /// Kasutab kujunditele vastavate klotsimustrite massiivi, samuti
        /// Totrise põhiklassist mänguväljaku vasaku ülanurga asukohavektorit
        /// </summary>
        /// <param name="spriteBatch">Eelnevalt avatud spritebatch</param>
        public void JoonistaKujund(SpriteBatch spriteBatch)
        {
            spriteBatch.Begin();

            for (int rida = 0; rida < 4; rida++)
            {
                for (int tulp = 0; tulp < 4; tulp++)
                {
                    if (andmed[liik, asend, rida, tulp] == 1)
                    {
                        Vector2 klotsiAsuKoht = new Vector2();
                        klotsiAsuKoht.X = Totris.vasakYlaNurk.X + (asuKohaTulp + tulp) * klotsiSuurus;
                        klotsiAsuKoht.Y = Totris.vasakYlaNurk.Y + (asuKohaRida + rida) * klotsiSuurus;

                        spriteBatch.Draw(Totris.klotsiPildid[liik], klotsiAsuKoht, Color.White);

                    }
                }
            }

            spriteBatch.End();
        }

        /// <summary>
        /// Joonistab järgmise klotsi ja paigutab selle järgmise klotsi aknakesse. 
        /// Kasutab kujunditele vastavate klotsimustrite massiivi, samuti 
        /// Totrise põhiklassist aknakese vasaku ülanurga asukohavektorit
        /// </summary>
        /// <param name="spriteBatch">Eelnevalt avatud spritebatch</param>

        public void JoonistaJargmineKujund(SpriteBatch spriteBatch)
        {
            spriteBatch.Begin();

            for (int rida = 0; rida < 4; rida++)
            {
                for (int tulp = 0; tulp < 4; tulp++)
                {
                    if (andmed[jargmiseLiik, 0, rida, tulp] == 1)
                    {
                        Vector2 klotsiAsuKoht = new Vector2();
                        klotsiAsuKoht.X = Totris.jargmiseVasakYlaNurk.X + tulp * klotsiSuurus;
                        klotsiAsuKoht.Y = Totris.jargmiseVasakYlaNurk.Y + rida * klotsiSuurus;

                        spriteBatch.Draw(Totris.klotsiPildid[jargmiseLiik], klotsiAsuKoht, Color.White);

                    }
                }
            }

            spriteBatch.End();
        }

        /// <summary>
        /// Tuvastab, kas kujundi liigutamisel ühe koha võrra üles, alla või paremale
        /// toimuks kokkupõrge väljaku ääre või teise kujundiga. 
        /// </summary>
        /// <param name="tase">Eraldi klassis defineeritud mängutase, millest sõltub
        /// ka mänguväljaku kõrgus</param>

        public void KokkuporgeteAvastamine(Tase tase)
        {
            // enne kokkupõrke tuvastamist eeldame,
            // et kokkupõrget ei ole
            AllKokkuPorge = false;
            YlalKokkuPorge = false;
            ParemKokkuPorge = false;
            VasakPoordeKokkuPorge = false;
            ParemPoordeKokkuPorge = false;

            // vaatame läbi kogu 4x4 ruudustiku, kus kujund asub 
            for (int rida = 0; rida < 4; rida++)
            {
                for (int tulp = 0; tulp < 4; tulp++)
                {
                    // Lihtkokkupõrget otsime siis, kui vaadeldavas ruudustiku
                    // pesas on klots olemas (väärtus on 1)                    
                    if (andmed[liik, asend, rida, tulp] == 1)
                    {
                        int r = asuKohaRida + rida;
                        int t = asuKohaTulp + tulp;

                        // Otsime kokkupõrget allpool. Kokkupõrge tekib siis, kui
                        // vaadeldav rida on alumise väljakuääre vastas või kui klotsist
                        // allpool asub teine kujund. NB! Oma kujundi teised klotsid võivad
                        // allpool asuda, kuna väljakuruudu väärtus on seni -1, kuni kujund
                        // on lõpuni laskunud ja kohale kinnitatud.

                        if (r == tase.ValjakuKorgus - 1)
                            AllKokkuPorge = true;

                        if (r != tase.ValjakuKorgus - 1 && tase.Valjak[t, r + 1] != -1)
                            AllKokkuPorge = true;

                        // Otsime kokkupõrget üleval. Kokkupõrge tekib siis, kui
                        // vaadeldav rida on ülemise väljakuääre vastas või kui klotsist ülalpool
                        // asub teine kujund. 
                        if (r == 0)
                            YlalKokkuPorge = true;

                        if (r != 0 && tase.Valjak[t, r - 1] != -1)
                            YlalKokkuPorge = true;

                        // Otsime kokkupõrget paremal. Kokkupõrge tekib siis, kui 
                        // klots asub väljaku paremääre vastas või kui temast paremal on teine
                        // kujund. 
                        if (t == tase.ValjakuLaius - 1)
                            ParemKokkuPorge = true;

                        if (t != tase.ValjakuLaius - 1 && tase.Valjak[t + 1, r] != -1)
                            ParemKokkuPorge = true;

                    } // end if

                    // Otsime kokkupõrget juhul, kui kujundit keerata päripäeva ehk paremale.
                    // Tuvastame esiteks uue asendi
                    int paremPoore = (asend + 3) % 4;

                    // Vaatame, kas uues asendis on antud ruudul klots
                    if (andmed[liik, paremPoore, rida, tulp] == 1)
                    {
                        int r = asuKohaRida + rida;
                        int t = asuKohaTulp + tulp;

                        // Kokkupõrge juhtub, kui uues asendis asuks klots
                        // väljapool mänguvälja
                        if (r < 0 ||
                            r > tase.ValjakuKorgus - 1 ||
                            t < 0 ||
                            t > tase.ValjakuLaius - 1)
                            ParemPoordeKokkuPorge = true;

                        // Kokkupõrge juhtub, kui uues asendis paigutuks klots
                        // kohale, kus juba on teine kujund ees
                        else if (tase.Valjak[t, r] != -1)
                            ParemPoordeKokkuPorge = true;
                    } // end if

                    // Otsime kokkupõrget juhul, kui kujundit keerata vastupäeva
                    // ehk vasakule.

                    // Tuvastame uue asendi                    
                    int vasakPoore = (asend + 1) % 4;

                    // Vaatame, kas uues asendis on ruudustiku vaadeldavas
                    // pesas klots
                    if (andmed[liik, vasakPoore, rida, tulp] == 1)
                    {
                        int r = asuKohaRida + rida;
                        int t = asuKohaTulp + tulp;

                        // Kokkupõrge juhtub, kui uues asendis asuks klots
                        // väljapool mänguvälja
                        if (r < 0 ||
                            r > tase.ValjakuKorgus - 1 ||
                            t < 0 ||
                            t > tase.ValjakuLaius - 1)
                            VasakPoordeKokkuPorge = true;

                        // Kokkupõrge juhtub, kui uues asendis paigutuks klots
                        // kohale, kus juba on teine kujund ees
                        else if (tase.Valjak[t, r] != -1)
                            VasakPoordeKokkuPorge = true;
                    } // end if
                } // end sisemine for-tsükkel
            } // end välimine for-tsükkel
        } // end KokkuPorgeteAvastamine


        /// <summary>
        /// Kui kujund jäetakse paika, muutub mänguvälja vastava ruudu väärtus
        /// -1 pealt vastavat kujundiliiki tähistavaks väärtuseks vahemikus 0-6
        /// </summary>
        /// <param name="tase">Eraldi klassis defineeritud mängutase, millest sõltub
        /// ka mänguväljaku kõrgus</param>
        public void JataKujundPaika(Tase tase)
        {
            for (int rida = 0; rida < 4; rida++)
                for (int tulp = 0; tulp < 4; tulp++)
                {
                    if (andmed[liik, asend, rida, tulp] == 1)
                    {
                        tase.Valjak[asuKohaTulp + tulp, asuKohaRida + rida] = liik;
                    }
                }
        }

    }
}
